package com.open.tool.dispatch.impl;

import com.open.base.dispatch.IGeneralConfigDispatch;
import com.open.base.model.CodeGenerate;
import com.open.base.model.DataSource;
import com.open.base.model.dto.UserConfigDto;
import com.open.common.exception.ServiceException;
import com.open.common.model.Page;
import com.open.common.utils.YamlUtil;
import com.open.generate.database.DBConnection;
import com.open.generate.database.MysqlSelectProperty;
import com.open.generate.dispatch.CodeGenerateDispatch;
import com.open.generate.model.TableData;
import com.open.tool.dispatch.IGenerateDispatch;
import lombok.extern.slf4j.Slf4j;
import org.apache.velocity.VelocityContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.ByteArrayOutputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipOutputStream;

import static com.open.common.enums.ConfigEnum.DataBase;
import static com.open.common.enums.ConfigEnum.Generate;

/**
 * @author dashu03
 * @date 2025年04月06日 14:12
 * @description
 */
@Slf4j
@Component
public class GenerateDispatchImpl implements IGenerateDispatch {

    @Autowired
    private MysqlSelectProperty mysqlSelectProperty;

    @Autowired
    private IGeneralConfigDispatch userConfigDispatch;

    @Autowired
    private CodeGenerateDispatch codeGenerateDispatch;

    @Override
    public Page<TableData> findPage(Page<TableData> page, TableData model) {
        Map<String, Object> map = new HashMap<String, Object>(4);
        int startPoint = (page.getIndex() - 1) * page.getSize();
        map.put("tableName", model.getTableName());
        map.put("tableComment", model.getTableComment());
        map.put("startPoint", startPoint);
        map.put("endPoint", page.getSize());
        Integer count = 0;
        try {
            count = mysqlSelectProperty.findPageCount(map);
            if (count > startPoint) {
                page.setItems(mysqlSelectProperty.findPage(map));
            } else {
                page.setItems(new ArrayList<TableData>());
            }
        } catch (SQLException e) {
            log.error("GenerateDispatchImpl findPage error", e);
            throw new ServiceException(e.getMessage());
        }
        page.setTotal(count);
        return page;
    }

    @Override
    public byte[] codeGenerate(List<String> tableNames) {
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
             ZipOutputStream zip = new ZipOutputStream(outputStream)) {
            // 获取配置信息
            CodeGenerate generate = this.FillGenerate();
            //填充代码生成器对象
            for (String tableName : tableNames) {
                generate.setTableName(tableName);
                this.GenerateSingle(zip, generate);
            }
            // 问题？ try-with-resources 不加finish无法向zip添加尾部信息
            zip.finish();
            return outputStream.toByteArray();
        } catch (Exception e) {
            log.error("生成ZIP文件失败", e);
            return new byte[0];
        }
    }

    private CodeGenerate FillGenerate() {
        CodeGenerate generateTem = (CodeGenerate) userConfigDispatch.getUserConfig(new UserConfigDto(Generate.getType()));
        CodeGenerate generate = YamlUtil.loadConfig(CodeGenerate.class, "config/config.yml");
        DataSource dataSource = (DataSource) userConfigDispatch.getUserConfig(new UserConfigDto(DataBase.getType()));
        generate.setDatabase(mysqlSelectProperty.getDatabaseNameFromUrl(dataSource.getUrl()));
        generate.setCurrentUser(generateTem.getCurrentUser());
        generate.setTableExclusion(generateTem.getTableExclusion());
        generate.setPathPrefix(generateTem.getPathPrefix());
        generate.setComment(generateTem.getComment());
        return generate;
    }

    /**
     * 单表生成代码
     *
     * @param codeGenerate
     */
    public boolean GenerateSingle(ZipOutputStream zipOut, CodeGenerate codeGenerate) {
        try {
            //表名转类名
            codeGenerateDispatch.tablesNameToClassName(codeGenerate);
            VelocityContext context = new VelocityContext();
            //构建文件路径
            codeGenerateDispatch.buildPath(context, codeGenerate);
            //构建数据库相关
            codeGenerateDispatch.buildDataBase(context, codeGenerate);
            //生成文件
            codeGenerateDispatch.buildFile(zipOut, context, codeGenerate);
        } catch (Exception e) {
            log.error("表名称:{}生成代码失败", codeGenerate.getTableName(), e);
            return false;
        }
        return true;
    }

    @Override
    public Boolean testConnection(DataSource dataSource) {
        try {
            // 连接失败直接抛出异常
            DBConnection.getConnection(dataSource);
            return true;
        } catch (SQLException e) {
            log.error("数据库连接失败", e);
            throw new ServiceException(e.getMessage());
        }
    }
}
